package com.muyan.sys.common.filter;



import com.alibaba.fastjson2.JSONObject;
import jakarta.servlet.*;
import jakarta.servlet.annotation.WebFilter;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import lombok.extern.slf4j.Slf4j;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.core.annotation.Order;
import org.springframework.http.MediaType;


import java.io.IOException;
import java.io.Reader;
import java.io.StringWriter;
import java.io.Writer;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Map;

@Slf4j
public class RequestLogFilter implements Filter {
    private static final Logger LOGGER = LoggerFactory.getLogger(RequestLogFilter.class);

    private static final int BUFFER_SIZE = 1024 * 8;

    @Override
    public void init(FilterConfig filterConfig) throws ServletException {

    }

    @Override
    public void doFilter(ServletRequest sRequest, ServletResponse sResponse, FilterChain chain) throws IOException, ServletException {
       
    	HttpServletRequest request = (HttpServletRequest) sRequest;
        HttpServletResponse response = (HttpServletResponse) sResponse;
        
    	String requestUrl = request.getRequestURL().toString();


        String method = request.getMethod();
        String contentType = request.getContentType()==null?"":request.getContentType();

        log.info("contentType={}",request);
        if(!contentType.contains(MediaType.MULTIPART_FORM_DATA_VALUE) && !contentType.contains(MediaType.APPLICATION_FORM_URLENCODED_VALUE)){
    		 
    		   ServletRequest requestWrapper = null;
             /********* 打印请求参数日志 End *************/
             //如果是POST请求并且不是文件上传
             log.info("contentType={}",contentType);
             log.info("method={}",method);

                 //重新生成ServletRequest  这个新的ServletRequest 获取流时会将流的数据重写进流里面
                 requestWrapper = new RequestReaderHttpServletRequestWrapper(request);
                 log.info("contentType={}",contentType);


    	        //获取请求中的流如何，将取出来的字符串，再次转换成流，然后把它放入到新request对象中。
    	        // 在chain.doFiler方法中传递新的request对象
    	        if(requestWrapper == null) {
    	            chain.doFilter(request, response);
    	        } else {
    	            /********* 打印请求参数日志 Start *************/
    	            Map<String, Object> resultMap = new HashMap<>();

    	            resultMap.put("requestUrl", requestUrl.toString());
    	            String header = request.getHeader("Authorization");
    	            resultMap.put("header", header);
                    if(!contentType.equals(MediaType.MULTIPART_FORM_DATA_VALUE)){
                        String requestBody = read(requestWrapper.getReader());
                        resultMap.put("requestBody", requestBody);
                    }

    	            Map<String, Object> paramMap = new HashMap<>();
    	            Enumeration enu = request.getParameterNames();
    	            while (enu.hasMoreElements()) {
    	                String paraName = (String) enu.nextElement();
    	                paramMap.put(paraName, request.getParameter(paraName));
    	            }
    	            resultMap.put("paramMap", paramMap);
    	            log.info(" REQUEST: " + request.getMethod() + " "+ JSONObject.toJSONString(resultMap));

    	            chain.doFilter(requestWrapper, response);
    	        } 
    		 
    	 } else {
    		 chain.doFilter(sRequest, response);
    	 }
    }

    @Override
    public void destroy() {

    }

    private String read(Reader reader) throws IOException {
        StringWriter writer = new StringWriter();
        try {
            write(reader, writer);
            return writer.getBuffer().toString();
        } finally {
            writer.close();
        }
    }

    private long write(Reader reader, Writer writer) throws IOException {
        return write(reader, writer, BUFFER_SIZE);
    }

    private long write(Reader reader, Writer writer, int bufferSize) throws IOException {
        int read;
        long total = 0;
        char[] buf = new char[BUFFER_SIZE];
        while ((read = reader.read(buf)) != -1) {
            writer.write(buf, 0, read);
            total += read;
        }
        return total;
    }

}
